﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HtmlAgilityPack;
using System.Text.RegularExpressions;
using System.Data;
using PanGu;
using System.Xml;
using System.IO;
using System.Windows;

namespace PatientInformationExtract.MainInterface.Models.XMLCS
{
    class ProcessNoteInfo : IHtmlInfo
    {
        private int _count;
        public string FileName
        {
            get
            {
                return @"病程记录$";
            }
        }
        private XmlDocument _xml;
        public XmlDocument XmlDoc { get { return this._xml; } }
        private List<XmlElement> _xmlElement;
        public List<XmlElement> XmlElements { get { return this._xmlElement; } }
        private string _filePath;
        public string FilePath { get { return this._filePath; } }
        private string _visitTime;
        public string VisitTime { get { return this._visitTime; } }
        private string _patientID;
        public string PatientID { get { return this._patientID; } }
        private string _visitID2;
        public string VisitID2 { get { return this._visitID2; } }
        private string _patientName;
        public string PatientName { get { return this._patientName; } }
        private string _gender;
        public string Gender { get { return this._gender; } }
        private string _age;
        public string Age { get { return this._age; } }
        private List<string> _dischargeDiagnosis;
        private List<string> _admissionDiagnosis;
        public List<string> Diagnosis
        {
            get
            {
                if (_dischargeDiagnosis.Count != 0)
                {
                    return _dischargeDiagnosis;
                }
                else
                {
                    return _admissionDiagnosis;
                }
            }
        }

        public List<string> DiagnosisDisplay
        {
            get
            {
                List<string> display = new List<string>();
                List<string> diagnosis;
                if (_dischargeDiagnosis.Count != 0)
                {
                    diagnosis = _dischargeDiagnosis;
                }
                else
                {
                    diagnosis = _admissionDiagnosis;
                }
                for (int i = 0; i < diagnosis.Count; i++)
                {
                    display.Add((i + 1).ToString() + "、" + diagnosis[i]);
                }
                return display;
            }
        }
        public int Count { get { return this._count; } }
        private HtmlDocument _doc;
        private List<int> _childNodesIndex;
        private Segment _segment;
        private List<ProcessNoteUnit> _notes;
        public List<ProcessNoteUnit> Notes { get { return this._notes; } }
        private bool _isInitialized;
        public bool IsInitialized { get { return this._isInitialized; } }

        public ProcessNoteInfo(XmlDocument xml)
        {
            _doc = new HtmlDocument();
            _patientID = null;
            _patientName = null;
            _visitID2 = null;
            _visitTime = null;
            _gender = null;
            _age = null;
            _filePath = null;
            _count = 0;
            _childNodesIndex = new List<int>();
            _segment = new Segment();
            _notes = new List<ProcessNoteUnit>();
            _xmlElement = new List<XmlElement>();
            _xml = xml;
            _isInitialized = false;
            _dischargeDiagnosis = new List<string>();
            _admissionDiagnosis = new List<string>();
        }

        public void SetXML(ref XmlDocument xml)
        {
            _xml = xml;
        }

        public void Initialize(string filePath)
        {
            if (!_isInitialized)
            {
                _filePath = filePath;
                _doc.Load(filePath);
                try
                {
                    this._patientName = _doc.DocumentNode.SelectSingleNode(@"/html[1]/body[1]/table[1]/tr[1]/td[1]/table[1]/tr[1]/td[1]/table[2]/tr[2]/td[1]/p[2]/span[2]").InnerText.Replace(@"&nbsp;", "");
                    this._patientID = _doc.DocumentNode.SelectSingleNode(@"/html[1]/body[1]/table[1]/tr[1]/td[1]/table[1]/tr[1]/td[1]/table[2]/tr[2]/td[5]/p[1]/span[2]").InnerText.Replace(@"&nbsp;", "");
                    this._visitID2 = _doc.DocumentNode.SelectSingleNode(@"/html[1]/body[1]/table[1]/tr[1]/td[1]/table[1]/tr[1]/td[1]/table[2]/tr[2]/td[5]/p[2]/span[2]").InnerText.Replace(@"&nbsp;", "");
                    this._visitTime = _doc.DocumentNode.SelectSingleNode(@"/html[1]/body[1]/table[1]/tr[1]/td[1]/table[1]/tr[1]/td[1]/p[4]/span[1]").InnerText.Replace(@"&nbsp;", " ");
                    try
                    {
                        this._gender = _doc.DocumentNode.SelectSingleNode(@"/html[1]/body[1]/table[1]/tr[1]/td[1]/table[1]/tr[1]/td[1]/p[5]/span[6]").InnerText.Replace(@"&nbsp;", " ");
                        this._age = _doc.DocumentNode.SelectSingleNode(@"/html[1]/body[1]/table[1]/tr[1]/td[1]/table[1]/tr[1]/td[1]/p[5]/span[8]").InnerText.Replace(@"&nbsp;", " ");
                    }
                    catch
                    {
                        string basicInfomation = _doc.DocumentNode.SelectSingleNode(@"/html[1]/body[1]/table[1]/tr[1]/td[1]/table[1]/tr[1]/td[1]/p[5]").InnerText.Replace(@"&nbsp;", " ");
                        Regex regexGender = new Regex(@"，(男|女)，");
                        Regex regexAge = new Regex(@"，(\d{1,}岁)，");
                        this._gender = regexGender.Match(basicInfomation).Groups[1].ToString();
                        this._age = regexAge.Match(basicInfomation).Groups[1].ToString();
                    }

                    HtmlNode node = _doc.DocumentNode.SelectSingleNode(@"/html[1]/body[1]/table[1]/tr[1]/td[1]/table[1]/tr[1]/td[1]");
                    Regex regex = new Regex(@"^\d\d\d\d-\d\d-\d\d(&nbsp;\d\d:\d\d)?");
                    foreach (HtmlNode n in node.ChildNodes.ToArray())
                    {
                        if (n.Name == "#text")
                        {
                            n.Remove();
                        }
                    }
                    for (int i = 0; i < node.ChildNodes.Count; i++)
                    {
                        if (node.ChildNodes[i].Name == "p")
                        {
                            Match match = regex.Match(node.ChildNodes[i].InnerText);
                            if (match.Success)
                            {
                                _childNodesIndex.Add(i);
                            }
                        }
                    }
                    _count = _childNodesIndex.Count;
                    for (int z = 0; z < _childNodesIndex.Count; z++)
                    {
                        ProcessNoteUnit note = new ProcessNoteUnit();
                        note.setTime(regex.Match(node.ChildNodes[_childNodesIndex[z]].InnerText).Value.Replace(@"&nbsp;", " "));
                        if (node.ChildNodes[_childNodesIndex[z]].ChildNodes.Count == 2)
                        {
                            note.setType(node.ChildNodes[_childNodesIndex[z]].ChildNodes[1].InnerText.Replace(@"&nbsp;", "").Trim());
                        }
                        if (z != _childNodesIndex.Count - 1)
                        {
                            string buffer = null;
                            for (int i = _childNodesIndex[z] + 1; i < _childNodesIndex[z + 1] - 1; i++)
                            {
                                buffer = buffer + node.ChildNodes[i].InnerText.Replace(@"&nbsp;", " ") + "\r\n";
                            }
                            if (z == 0)
                            {
                                Regex regexAdmissionDiagnosis = new Regex(@"三、初步诊断：(.*)四、诊疗计划");
                                if (regexAdmissionDiagnosis.IsMatch(buffer.Replace("\r\n", "").Replace("。", "").Trim()))
                                {
                                    string diagnosis = regexAdmissionDiagnosis.Match(buffer.Replace("\r\n", "").Trim()).Groups[1].ToString().Replace("：", "").Replace("。", "").Trim();
                                    Regex regexLastIndex = new Regex(@"(\d)\.");
                                    if (regexLastIndex.IsMatch(diagnosis))
                                    {
                                        int lastIndex = int.Parse(regexLastIndex.Matches(diagnosis)[regexLastIndex.Matches(diagnosis).Count - 1].Groups[1].ToString());
                                        if (lastIndex > 1)
                                        {
                                            for (int i = 1; i < lastIndex; i++)
                                            {
                                                _admissionDiagnosis.Add(new Regex(i.ToString() + @"\.(.*)" + (i + 1).ToString() + @"\.").Match(diagnosis).Groups[1].ToString());
                                            }
                                        }
                                        _admissionDiagnosis.Add(new Regex(lastIndex.ToString() + @"\.(.*)$").Match(diagnosis).Groups[1].ToString());
                                    }
                                    else
                                    {
                                        _admissionDiagnosis.Add(diagnosis);
                                    }
                                }
                            }
                            note.setWords(_segment.DoSegment(buffer, true));
                            note.setDoctor(node.ChildNodes[_childNodesIndex[z + 1] - 1].InnerText.Replace(@"&nbsp;", "").Trim());
                        }
                        else
                        {
                            string buffer = null;
                            int endIndex = 0;
                            for (int i = node.ChildNodes.Count - 1; i > 0; i--)
                            {
                                if (node.ChildNodes[i].InnerText.Replace(@"&nbsp;", "").Replace("\r", "").Replace("\n", "").Trim() != "")
                                {
                                    note.setDoctor(node.ChildNodes[_childNodesIndex[z] - 1].InnerText.Replace(@"&nbsp;", "").Trim());
                                    endIndex = i;
                                    break;
                                }
                            }
                            for (int i = _childNodesIndex[z] + 1; i < endIndex; i++)
                            {
                                buffer = buffer + node.ChildNodes[i].InnerText.Replace(@"&nbsp;", " ") + "\r\n";
                            }
                            Regex regexDischargeDiagnosis = new Regex(@"出院诊断(.*)出院医嘱");
                            if (regexDischargeDiagnosis.IsMatch(buffer.Replace("\r\n", "").Trim()))
                            {
                                string diagnosis = regexDischargeDiagnosis.Match(buffer.Replace("\r\n", "").Trim()).Groups[1].ToString().Replace("：", "").Replace("。", "").Trim();
                                Regex regexLastIndex = new Regex(@"(\d)\.");
                                if (regexLastIndex.IsMatch(diagnosis))
                                {
                                    int lastIndex = int.Parse(regexLastIndex.Matches(diagnosis)[regexLastIndex.Matches(diagnosis).Count - 1].Groups[1].ToString());
                                    if (lastIndex > 1)
                                    {
                                        for (int i = 1; i < lastIndex; i++)
                                        {
                                            _dischargeDiagnosis.Add(new Regex(i.ToString() + @"\.(.*)" + (i + 1).ToString() + @"\.").Match(diagnosis).Groups[1].ToString());
                                        }
                                    }
                                    _dischargeDiagnosis.Add(new Regex(lastIndex.ToString() + @"\.(.*)$").Match(diagnosis).Groups[1].ToString());
                                }
                                else
                                {
                                    _dischargeDiagnosis.Add(diagnosis);
                                }
                            }
                            note.setWords(_segment.DoSegment(buffer, true));
                        }
                        _notes.Add(note);
                    }
                    AddToXmlElement();
                    _doc = null;
                    _isInitialized = true;
                }
                catch (Exception ex)
                {
                    _doc = null;
                    throw new Exception(String.Format(PatientInfoErrorMessages.InitializationFailed, "ProcessNoteInfo", ex.Message), ex);
                }
            }
            else
            {
                throw new Exception(String.Format(PatientInfoErrorMessages.AlreadyInitialized, "ProcessNoteInfo"));
            }

        }

        private void AddToXmlElement()
        {
            Regex regexSurgery = new Regex(@"(\w+术)记录");
            Regex regexCheck = new Regex(@"(\w+查房)记录");
            foreach (ProcessNoteUnit unit in _notes)
            {
                if (unit.Type != null)
                {
                    if (regexSurgery.IsMatch(unit.Type))
                    {
                        _xmlElement.Add(NewMedicalInterventionElement(regexSurgery.Match(unit.Type).Groups[1].ToString(), unit.Time, "S"));
                    }
                    if (regexCheck.IsMatch(unit.Type))
                    {
                        _xmlElement.Add(NewMedicalInterventionElement(regexCheck.Match(unit.Type).Groups[1].ToString(), unit.Time, "C"));
                    }
                }
                List<WordInfo> words = new List<WordInfo>();
                foreach (WordInfo word in unit.Words)
                {
                    if (word.WordType.Equals(WordType.Synonym))
                    {
                        words.RemoveAt(words.Count - 1);
                    }
                    words.Add(word);
                }
                for (int i = 0; i < words.Count; i++)
                {
                    if (words[i].Pos.Equals(POS.POS_U_O))
                    {
                        bool match = false;
                        int position = 0;
                        if (i != 0 && i != words.Count)
                        {
                            if (words[i - 1].Pos.Equals(POS.POS_U_D))
                            {
                                match = !match;
                                position = -1;
                            }
                            if (words[i + 1].Pos.Equals(POS.POS_U_D))
                            {
                                match = !match;
                                position = 1;
                            }
                        }
                        if (match)
                        {
                            _xmlElement.Add(NewObservationElement(words[i].Word, unit.Time, words[i + position].Word));
                        }
                    }

                }
            }
        }

        private XmlElement NewMedicalInterventionElement(string name, string occurTime, string type)
        {
            XmlElement medicalInterventionE = _xml.CreateElement("MedicalIntervention");
            XmlElement nameE = _xml.CreateElement("Name");
            XmlElement originalSourceE = _xml.CreateElement("OriginalSource");
            if (occurTime != "")
            {
                DateTime time = Convert.ToDateTime(occurTime);
                occurTime = time.ToString("yyyy-MM-ddTHH:mm:ssZ");
            }
            medicalInterventionE.SetAttribute("OccurTime", occurTime);
            medicalInterventionE.SetAttribute("Type", type);
            nameE.InnerText = name;
            medicalInterventionE.AppendChild(nameE);
            originalSourceE.InnerText = "HTML";
            medicalInterventionE.AppendChild(originalSourceE);
            return medicalInterventionE;
        }

        private XmlElement NewObservationElement(string name, string occurTime, string result)
        {
            XmlElement observationE = _xml.CreateElement("Observation");
            XmlElement nameE = _xml.CreateElement("Name");
            XmlElement resultE = _xml.CreateElement("Result");
            XmlElement originalSourceE = _xml.CreateElement("OriginalSource");
            if (occurTime != "")
            {
                DateTime time = Convert.ToDateTime(occurTime);
                occurTime = time.ToString("yyyy-MM-ddTHH:mm:ssZ");
            }
            observationE.SetAttribute("OccurTime", occurTime);
            observationE.SetAttribute("Type", "ProcessNote");
            resultE.InnerText = result;
            nameE.InnerText = name;
            observationE.AppendChild(nameE);
            observationE.AppendChild(resultE);
            originalSourceE.InnerText = "HTML";
            observationE.AppendChild(originalSourceE);
            return observationE;
        }
    }
}

